package com.tian.excel.config;

import cn.hutool.json.JSONUtil;
import com.tian.excel.filter.LoginFilter;
import com.tian.excel.service.impl.MyUserDetailsService;
import com.tian.excel.utils.JWTUtil;
import com.tian.excel.vo.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author: Tian
 * @version: 1.0
 * @since: 1.0
 * @date: 2024/7/27/10:43
 */
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Autowired
    private LoginFilter loginFilter;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    private String name;



    @Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder;

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);



        /*auth.
                //基于内存完成认证和授权
                inMemoryAuthentication()
                //表示用户名
                .withUser("run")
                //密码
                .password(passwordEncoder().encode("run"))
                //表示当前用户具有的角色
                .roles("admin")
                .authorities("user:select")
                .authorities("dept:hello")
                .and()
                .withUser("tian")
                .password(passwordEncoder().encode("tian"))
                .roles("admin")
                .authorities("user:select");*/
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(loginFilter, UsernamePasswordAuthenticationFilter.class);
        http.formLogin()
                //登录页面;
                .loginPage("/login.html")
                //登录的处理路径 默认 /login
                .loginProcessingUrl("/login")
                .successHandler(successHandler())
                .failureHandler(failureHandler())
                //登录成功转发的路径 必须为post请求
                //.successForwardUrl("/success")
                //登录失败转发的路径 必须为post请求
                //.failureForwardUrl("/error1")
                //上面的请求路径无需认证
                .permitAll();


        http.logout(item->{
            item.logoutSuccessHandler((httpServletRequest, httpServletResponse, e) -> {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter writer = httpServletResponse.getWriter();
                stringRedisTemplate.delete("token:"+name);
                R r=new R(200,"退出成功",null);
                String jsonString =JSONUtil.toJsonStr(r);
                writer.println(jsonString);
                writer.flush();
                writer.close();
            });
        });

        //指定权限不够跳转的页面
        //http.exceptionHandling().accessDeniedPage("/403.html");
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());

        //允许/login跨域
        http.cors();


        //禁用跨域伪造请求的过滤器
        http.csrf().disable();
       /* http.authorizeRequests()
                .antMatchers("/dept/hello").hasAnyAuthority("dept:hello");*/
        //除了上的请求,其他请求都需要认证
        http.authorizeRequests()
                .antMatchers("/error.html","/doc.html","/css/**","/js/**","/images/**","/webjars/bycdao-ui/**","/swagger-resources/**","/v2/**").permitAll()
                .anyRequest().authenticated();



    }



       /* @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/error.html","/doc.html");
        }*/


    //登录成功后的处理
    private AuthenticationSuccessHandler successHandler(){
        return (httpServletRequest, httpServletResponse, authentication) -> {
            System.out.println("====登录成功========");
            //设置响应的编码
            httpServletResponse.setContentType("application/json;charset=utf-8");
            //获取输出对象
            PrintWriter writer = httpServletResponse.getWriter();
            //返回json数据即可
            Map<String,Object> map=new HashMap<>();
            map.put("username",authentication.getName());
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            //获取权限
            List<String> collect = authorities.stream().map(item -> item.getAuthority()).collect(Collectors.toList());

            map.put("permissions",collect);
            String token = JWTUtil.createToken(map);
            stringRedisTemplate.opsForValue().set("token:"+authentication.getName(),token,30, TimeUnit.MINUTES);
            name = authentication.getName();
            //返回一个统一的json对象
            R r=new R(200,"登录成功",token);
            //转换为json字符串
            String jsonString = JSONUtil.toJsonStr(r);
            //servlet
            writer.println(jsonString);
            writer.flush();
            writer.close();
        };
    }

    //登录失败后的处理
    private AuthenticationFailureHandler failureHandler(){

        return (httpServletRequest, httpServletResponse, e) -> {
            System.out.println("=========登录失败=========");
            httpServletResponse.setContentType("application/json;charset=utf-8");
            PrintWriter writer = httpServletResponse.getWriter();
            R r=new R(500,"登录失败",e.getMessage());
            String jsonString = JSONUtil.toJsonStr(r);
            writer.println(jsonString);
            writer.flush();
            writer.close();
        };

    }


    //权限不足时的处理函数
    private AccessDeniedHandler accessDeniedHandler(){
        return (httpServletRequest, httpServletResponse, e) -> {
            httpServletResponse.setContentType("application/json;charset=utf-8");
            PrintWriter writer = httpServletResponse.getWriter();
            R r=new R(403,"权限不足",e.getMessage());
            String jsonString =JSONUtil.toJsonStr(r);
            writer.println(jsonString);
            writer.flush();
            writer.close();
        };
    }


}
